home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / vid_vga.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  10KB  |  479 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. //
  21. // vid_vga.c: VGA-specific DOS video stuff
  22. //
  23.  
  24. // TODO: proper handling of page-swap failure
  25.  
  26. #include <dos.h>
  27.  
  28. #include "quakedef.h"
  29. #include "d_local.h"
  30. #include "dosisms.h"
  31. #include "vid_dos.h"
  32. #include <dpmi.h>
  33.  
  34. extern regs_t regs;
  35.  
  36. int        VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes;
  37. byte    *VGA_pagebase;
  38. vmode_t    *VGA_pcurmode;
  39.  
  40. static int        VGA_planar;
  41. static int        VGA_numpages;
  42. static int        VGA_buffersize;
  43.  
  44. void    *vid_surfcache;
  45. int        vid_surfcachesize;
  46.  
  47. int        VGA_highhunkmark;
  48.  
  49. #include "vgamodes.h"
  50.  
  51. #define NUMVIDMODES        (sizeof(vgavidmodes) / sizeof(vgavidmodes[0]))
  52.  
  53. void VGA_UpdatePlanarScreen (void *srcbuffer);
  54.  
  55. static byte    backingbuf[48*24];
  56.  
  57. /*
  58. ================
  59. VGA_BeginDirectRect
  60. ================
  61. */
  62. void VGA_BeginDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode, int x,
  63.     int y, byte *pbitmap, int width, int height)
  64. {
  65.     int        i, j, k, plane, reps, repshift;
  66.  
  67.     if (!lvid->direct)
  68.         return;
  69.  
  70.     if (lvid->aspect > 1.5)
  71.     {
  72.         reps = 2;
  73.         repshift = 1;
  74.     }
  75.     else
  76.     {
  77.         reps = 1;
  78.         repshift = 0;
  79.     }
  80.  
  81.     if (pcurrentmode->planar)
  82.     {
  83.         for (plane=0 ; plane<4 ; plane++)
  84.         {
  85.         // select the correct plane for reading and writing
  86.             outportb (SC_INDEX, MAP_MASK);
  87.             outportb (SC_DATA, 1 << plane);
  88.             outportb (GC_INDEX, READ_MAP);
  89.             outportb (GC_DATA, plane);
  90.  
  91.             for (i=0 ; i<(height << repshift) ; i += reps)
  92.             {
  93.                 for (k=0 ; k<reps ; k++)
  94.                 {
  95.                     for (j=0 ; j<(width >> 2) ; j++)
  96.                     {
  97.                         backingbuf[(i + k) * 24 + (j << 2) + plane] =
  98.                                 lvid->direct[(y + i + k) * VGA_rowbytes +
  99.                                 (x >> 2) + j];
  100.                         lvid->direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
  101.                                 pbitmap[(i >> repshift) * 24 +
  102.                                 (j << 2) + plane];
  103.                     }
  104.                 }
  105.             }
  106.         }
  107.     }
  108.     else
  109.     {
  110.         for (i=0 ; i<(height << repshift) ; i += reps)
  111.         {
  112.             for (j=0 ; j<reps ; j++)
  113.             {
  114.                 memcpy (&backingbuf[(i + j) * 24],
  115.                         lvid->direct + x + ((y << repshift) + i + j) *
  116.                          VGA_rowbytes,
  117.                         width);
  118.                 memcpy (lvid->direct + x + ((y << repshift) + i + j) *
  119.                          VGA_rowbytes,
  120.                         &pbitmap[(i >> repshift) * width],
  121.                         width);
  122.             }
  123.         }
  124.     }
  125. }
  126.  
  127.  
  128. /*
  129. ================
  130. VGA_EndDirectRect
  131. ================
  132. */
  133. void VGA_EndDirectRect (viddef_t *lvid, struct vmode_s *pcurrentmode, int x,
  134.     int y, int width, int height)
  135. {
  136.     int        i, j, k, plane, reps, repshift;
  137.  
  138.     if (!lvid->direct)
  139.         return;
  140.  
  141.     if (lvid->aspect > 1.5)
  142.     {
  143.         reps = 2;
  144.         repshift = 1;
  145.     }
  146.     else
  147.     {
  148.         reps = 1;
  149.         repshift = 0;
  150.     }
  151.  
  152.     if (pcurrentmode->planar)
  153.     {
  154.         for (plane=0 ; plane<4 ; plane++)
  155.         {
  156.         // select the correct plane for writing
  157.             outportb (SC_INDEX, MAP_MASK);
  158.             outportb (SC_DATA, 1 << plane);
  159.  
  160.             for (i=0 ; i<(height << repshift) ; i += reps)
  161.             {
  162.                 for (k=0 ; k<reps ; k++)
  163.                 {
  164.                     for (j=0 ; j<(width >> 2) ; j++)
  165.                     {
  166.                         lvid->direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] =
  167.                                 backingbuf[(i + k) * 24 + (j << 2) + plane];
  168.                     }
  169.                 }
  170.             }
  171.         }
  172.     }
  173.     else
  174.     {
  175.         for (i=0 ; i<(height << repshift) ; i += reps)
  176.         {
  177.             for (j=0 ; j<reps ; j++)
  178.             {
  179.                 memcpy (lvid->direct + x + ((y << repshift) + i + j) *
  180.                          VGA_rowbytes,
  181.                         &backingbuf[(i + j) * 24],
  182.                         width);
  183.             }
  184.         }
  185.     }
  186. }
  187.  
  188.  
  189. /*
  190. ================
  191. VGA_Init
  192. ================
  193. */
  194. void VGA_Init (void)
  195. {
  196.     int        i;
  197.  
  198. // link together all the VGA modes
  199.     for (i=0 ; i<(NUMVIDMODES - 1) ; i++)
  200.     {
  201.         vgavidmodes[i].pnext = &vgavidmodes[i+1];
  202.     }
  203.  
  204. // add the VGA modes at the start of the mode list
  205.     vgavidmodes[NUMVIDMODES-1].pnext = pvidmodes;
  206.     pvidmodes = &vgavidmodes[0];
  207.  
  208.     numvidmodes += NUMVIDMODES;
  209. }
  210.  
  211.  
  212. /*
  213. ================
  214. VGA_WaitVsync
  215. ================
  216. */
  217. void VGA_WaitVsync (void)
  218. {
  219.     while ((inportb (0x3DA) & 0x08) == 0)
  220.         ;
  221. }
  222.  
  223.  
  224. /*
  225. ================
  226. VGA_ClearVideoMem
  227. ================
  228. */
  229. void VGA_ClearVideoMem (int planar)
  230. {
  231.  
  232.     if (planar)
  233.     {
  234.     // enable all planes for writing
  235.         outportb (SC_INDEX, MAP_MASK);
  236.         outportb (SC_DATA, 0x0F);
  237.     }
  238.  
  239.     Q_memset (VGA_pagebase, 0, VGA_rowbytes * VGA_height);
  240. }
  241.  
  242. /*
  243. ================
  244. VGA_FreeAndAllocVidbuffer
  245. ================
  246. */
  247. qboolean VGA_FreeAndAllocVidbuffer (viddef_t *lvid, int allocnewbuffer)
  248. {
  249.     int        tsize, tbuffersize;
  250.  
  251.     if (allocnewbuffer)
  252.     {
  253.     // alloc an extra line in case we want to wrap, and allocate the z-buffer
  254.         tbuffersize = (lvid->rowbytes * (lvid->height + 1)) +
  255.                 (lvid->width * lvid->height * sizeof (*d_pzbuffer));
  256.     }
  257.     else
  258.     {
  259.     // just allocate the z-buffer
  260.         tbuffersize = lvid->width * lvid->height * sizeof (*d_pzbuffer);
  261.     }
  262.  
  263.     tsize = D_SurfaceCacheForRes (lvid->width, lvid->height);
  264.  
  265.     tbuffersize += tsize;
  266.  
  267. // see if there's enough memory, allowing for the normal mode 0x13 pixel,
  268. // z, and surface buffers
  269.     if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
  270.          0x10000 * 3) < minimum_memory)
  271.     {
  272.         Con_Printf ("Not enough memory for video mode\n");
  273.         VGA_pcurmode = NULL;    // so no further accesses to the buffer are
  274.                                 //  attempted, particularly when clearing
  275.         return false;        // not enough memory for mode
  276.     }
  277.  
  278.     VGA_buffersize = tbuffersize;
  279.     vid_surfcachesize = tsize;
  280.  
  281.     if (d_pzbuffer)
  282.     {
  283.         D_FlushCaches ();
  284.         Hunk_FreeToHighMark (VGA_highhunkmark);
  285.         d_pzbuffer = NULL;
  286.     }
  287.  
  288.     VGA_highhunkmark = Hunk_HighMark ();
  289.  
  290.     d_pzbuffer = Hunk_HighAllocName (VGA_buffersize, "video");
  291.  
  292.     vid_surfcache = (byte *)d_pzbuffer
  293.         + lvid->width * lvid->height * sizeof (*d_pzbuffer);
  294.     
  295.     if (allocnewbuffer)
  296.     {
  297.         lvid->buffer = (void *)( (byte *)vid_surfcache + vid_surfcachesize);
  298.         lvid->conbuffer = lvid->buffer;
  299.     }
  300.  
  301.     return true;
  302. }
  303.  
  304.  
  305. /*
  306. ================
  307. VGA_CheckAdequateMem
  308. ================
  309. */
  310. qboolean VGA_CheckAdequateMem (int width, int height, int rowbytes,
  311.     int allocnewbuffer)
  312. {
  313.     int        tbuffersize;
  314.  
  315.     tbuffersize = width * height * sizeof (*d_pzbuffer);
  316.  
  317.     if (allocnewbuffer)
  318.     {
  319.     // alloc an extra line in case we want to wrap, and allocate the z-buffer
  320.         tbuffersize += (rowbytes * (height + 1));
  321.     }
  322.  
  323.     tbuffersize += D_SurfaceCacheForRes (width, height);
  324.  
  325. // see if there's enough memory, allowing for the normal mode 0x13 pixel,
  326. // z, and surface buffers
  327.     if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 +
  328.          0x10000 * 3) < minimum_memory)
  329.     {
  330.         return false;        // not enough memory for mode
  331.     }
  332.  
  333.     return true;
  334. }
  335.  
  336.  
  337. /*
  338. ================
  339. VGA_InitMode
  340. ================
  341. */
  342. int VGA_InitMode (viddef_t *lvid, vmode_t *pcurrentmode)
  343. {
  344.     vextra_t        *pextra;
  345.  
  346.     pextra = pcurrentmode->pextradata;
  347.  
  348.     if (!VGA_FreeAndAllocVidbuffer (lvid, pextra->vidbuffer))
  349.         return -1;    // memory alloc failed
  350.  
  351.     if (VGA_pcurmode)
  352.         VGA_ClearVideoMem (VGA_pcurmode->planar);
  353.  
  354. // mode 0x13 is the base for all the Mode X-class mode sets
  355.     regs.h.ah = 0;
  356.     regs.h.al = 0x13;
  357.     dos_int86(0x10);
  358.  
  359.     VGA_pagebase = (void *)real2ptr(0xa0000);
  360.     lvid->direct = (pixel_t *)VGA_pagebase;
  361.  
  362. // set additional registers as needed
  363.     VideoRegisterSet (pextra->pregset);
  364.  
  365.     VGA_numpages = 1;
  366.     lvid->numpages = VGA_numpages;
  367.  
  368.     VGA_width = (lvid->width + 0x1F) & ~0x1F;
  369.     VGA_height = lvid->height;
  370.     VGA_planar = pcurrentmode->planar;
  371.     if (VGA_planar)
  372.         VGA_rowbytes = lvid->rowbytes / 4;
  373.     else
  374.         VGA_rowbytes = lvid->rowbytes;
  375.     VGA_bufferrowbytes = lvid->rowbytes;
  376.     lvid->colormap = host_colormap;
  377.     lvid->fullbright = 256 - LittleLong (*((int *)lvid->colormap + 2048));
  378.  
  379.     lvid->maxwarpwidth = WARP_WIDTH;
  380.     lvid->maxwarpheight = WARP_HEIGHT;
  381.  
  382.     lvid->conbuffer = lvid->buffer;
  383.     lvid->conrowbytes = lvid->rowbytes;
  384.     lvid->conwidth = lvid->width;
  385.     lvid->conheight = lvid->height;
  386.  
  387.     VGA_pcurmode = pcurrentmode;
  388.  
  389.     VGA_ClearVideoMem (pcurrentmode->planar);
  390.  
  391.     if (_vid_wait_override.value)
  392.     {
  393.         Cvar_SetValue ("vid_wait", (float)VID_WAIT_VSYNC);
  394.     }
  395.     else
  396.     {
  397.         Cvar_SetValue ("vid_wait", (float)VID_WAIT_NONE);
  398.     }
  399.  
  400.     D_InitCaches (vid_surfcache, vid_surfcachesize);
  401.  
  402.     return 1;
  403. }
  404.  
  405.  
  406. /*
  407. ================
  408. VGA_SetPalette
  409. ================
  410. */
  411. void VGA_SetPalette(viddef_t *lvid, vmode_t *pcurrentmode, unsigned char *pal)
  412. {
  413.     int shiftcomponents=2;
  414.     int i;
  415.  
  416.     UNUSED(lvid);
  417.     UNUSED(pcurrentmode);
  418.  
  419.     dos_outportb(0x3c8, 0);
  420.     for (i=0 ; i<768 ; i++)
  421.         outportb(0x3c9, pal[i]>>shiftcomponents);
  422. }
  423.  
  424.  
  425. /*
  426. ================
  427. VGA_SwapBuffersCopy
  428. ================
  429. */
  430. void VGA_SwapBuffersCopy (viddef_t *lvid, vmode_t *pcurrentmode,
  431.     vrect_t *rects)
  432. {
  433.  
  434.     UNUSED(pcurrentmode);
  435.  
  436. // TODO: can write a dword at a time
  437. // TODO: put in ASM
  438. // TODO: copy only specified rectangles
  439.     if (VGA_planar)
  440.     {
  441.  
  442.     // TODO: copy only specified rectangles
  443.  
  444.         VGA_UpdatePlanarScreen (lvid->buffer);
  445.     }
  446.     else
  447.     {
  448.         while (rects)
  449.         {
  450.             VGA_UpdateLinearScreen (
  451.                     lvid->buffer + rects->x + (rects->y * lvid->rowbytes),
  452.                      VGA_pagebase + rects->x + (rects->y * VGA_rowbytes),
  453.                     rects->width,
  454.                     rects->height,
  455.                     lvid->rowbytes,
  456.                     VGA_rowbytes);
  457.  
  458.             rects = rects->pnext;
  459.         }
  460.     }
  461. }
  462.  
  463.  
  464. /*
  465. ================
  466. VGA_SwapBuffers
  467. ================
  468. */
  469. void VGA_SwapBuffers (viddef_t *lvid, vmode_t *pcurrentmode, vrect_t *rects)
  470. {
  471.     UNUSED(lvid);
  472.  
  473.     if (vid_wait.value == VID_WAIT_VSYNC)
  474.         VGA_WaitVsync ();
  475.  
  476.     VGA_SwapBuffersCopy (lvid, pcurrentmode, rects);
  477. }
  478.  
  479.